/*
 * 版权所有 © 成都太阳高科技有限责任公司
 * http://www.suncd.com
 */
package cn.stylefeng.guns.utils.pdf;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.stylefeng.guns.modular.oss.cloud.OSSFactory;
import cn.stylefeng.guns.modular.wms.model.result.*;
import cn.stylefeng.guns.utils.DateUtils;
import cn.stylefeng.guns.utils.json.ValidatorUtils;
import com.lowagie.text.pdf.BaseFont;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ResourceUtils;
import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer;
import org.w3c.dom.Document;
import org.xhtmlrenderer.pdf.ITextFontResolver;
import org.xhtmlrenderer.pdf.ITextRenderer;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.*;
import java.text.DecimalFormat;
import java.util.List;
import java.util.Map;

/**
 * 功能：pdf处理工具类
 *
 * @author qust
 * @version 1.0 2018/2/23 17:21
 */
public class PdfUtils {
    private PdfUtils() {
    }

    private static final Logger LOGGER = LoggerFactory.getLogger(PdfUtils.class);

    /**
     * 按模板和参数生成html字符串
     *
     * @param templateName freemarker模板名称
     * @param variables    freemarker模板参数
     * @return String
     *
     * 解决打包后Windows下调用出现空指针问题
     */
    private static String generateDocString(FreeMarkerConfigurer configurer, String templateName, Object variables){
        StringWriter writer = new StringWriter();
        try {
            Template template = configurer.getConfiguration().getTemplate(templateName);
            template.process(variables, writer);
        }catch (Exception e){
            LOGGER.error(e.getMessage(),e);
        }
        writer.flush();
        return writer.toString();
    }
    /**
     * 按模板和参数生成html字符串,再转换为flying-saucer识别的Document
     *
     * @param templateName freemarker模板名称
     * @param variables    freemarker模板参数
     * @return Document
     *
     * Deprecated暂停使用, 调整为generateDocString()进行生成
     */
    @Deprecated
    private static Document generateDoc(FreeMarkerConfigurer configurer, String templateName, Map<String, Object> variables)  {
        Template tp;
        try {
            tp = configurer.getConfiguration().getTemplate(templateName);
        } catch (IOException e) {
            LOGGER.error(e.getMessage(), e);
            return null;
        }
        StringWriter stringWriter = new StringWriter();
        try(BufferedWriter writer = new BufferedWriter(stringWriter)) {
            try {
                tp.process(variables, writer);
                writer.flush();
            } catch (TemplateException e) {
                LOGGER.error("模板不存在或者路径错误", e);
            } catch (IOException e) {
                LOGGER.error("IO异常", e);
            }
            DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
            return builder.parse(new ByteArrayInputStream(stringWriter.toString().getBytes()));
        }catch (Exception e){
            LOGGER.error(e.getMessage(), e);
            return null;
        }
    }

    /**
     * 核心: 根据freemarker模板生成pdf文档
     *
     * @param configurer   freemarker配置
     * @param templateName freemarker模板名称
     * @param out          输出流
     * @param listVars     freemarker模板参数
     * @throws Exception   模板无法找到、模板语法错误、IO异常
     */
    private static void generateAll(FreeMarkerConfigurer configurer, String templateName, OutputStream out, List<Map<String, Object>> listVars, ResumeResult resumeResult) throws Exception {
        if (CollectionUtils.isEmpty(listVars)) {
            LOGGER.warn("警告:freemarker模板参数为空!");
            return;
        }
        ITextRenderer renderer = new ITextRenderer();
//        组装参数
        ResumeVo cgxVo = new ResumeVo();
        SubResumeVo subVo = createData(resumeResult);
        cgxVo.setResume(subVo);
        String doc = generateDocString(configurer, templateName, cgxVo);
        System.setProperty("javax.xml.transform.TransformerFactory", "com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl");
        renderer.setDocumentFromString(doc);
        //设置字符集(宋体),此处必须与模板中的<body style="font-family: SimSun">一致,区分大小写,不能写成汉字"宋体"
        ITextFontResolver fontResolver = (ITextFontResolver)renderer.getSharedContext().getFontResolver();
        fontResolver.addFont("fonts/simsun.ttc", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
        fontResolver.addFont("fonts/GB2312.ttf", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
        fontResolver.addFont("fonts/fzhtjw.ttf", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
        //展现和输出pdf
        renderer.layout();
        renderer.createPDF(out, false);

        //根据参数集个数循环调用模板,追加到同一个pdf文档中
        //(注意:此处从1开始,因为第0是创建pdf,从1往后则向pdf中追加内容)
        for (int i = 1; i < listVars.size(); i++) {
            String docAppend = generateDocString(configurer, templateName, listVars.get(i));
            renderer.setDocumentFromString(docAppend);
            renderer.layout();
            renderer.writeNextDocument(); //写下一个pdf页面
        }
        renderer.finishPDF(); //完成pdf写入
    }

    /**
     * pdf下载
     *
     * @param configurer   freemarker配置
     * @param templateName freemarker模板名称(带后缀.ftl)
     * @param listVars     模板参数集
     * @param response     HttpServletResponse
     * @param fileName     下载文件名称(带文件扩展名后缀)
     */
    public static void download(FreeMarkerConfigurer configurer, String templateName, List<Map<String, Object>> listVars, HttpServletResponse response, String fileName, ResumeResult resumeResult) {
        // 设置编码、文件ContentType类型、文件头、下载文件名
        response.setCharacterEncoding("utf-8");
        response.setContentType("multipart/form-data");
        try {
            response.setHeader("Content-Disposition", "attachment;fileName=" +
                    new String(fileName.getBytes("gb2312"), "ISO8859-1"));
        } catch (UnsupportedEncodingException e) {
            LOGGER.error(e.getMessage(), e);
        }
        try (ServletOutputStream out = response.getOutputStream()) {
            generateAll(configurer, templateName, out, listVars,resumeResult);
            out.flush();
        } catch (Exception e) {
            LOGGER.error(e.getMessage(), e);
        }
    }

    /**
     * pdf预览
     *
     * @param configurer   freemarker配置
     * @param templateName freemarker模板名称(带后缀.ftl)
     * @param listVars     模板参数集
     * @param response     HttpServletResponse
     */
    public static void preview(FreeMarkerConfigurer configurer, String templateName, List<Map<String, Object>> listVars, HttpServletResponse response, ResumeResult resumeResult) {
        try (ServletOutputStream out = response.getOutputStream()) {
            generateAll(configurer, templateName, out, listVars,resumeResult);
            out.flush();
        } catch (Exception e) {
            LOGGER.error(e.getMessage(), e);
        }
    }

    /**
     * pdf生成
     *
     * @param configurer   freemarker配置
     * @param templateName freemarker模板名称(带后缀.ftl)
     * @param listVars     模板参数集
     */
    public static FileInfo createPdfFile(FreeMarkerConfigurer configurer, String templateName, List<Map<String, Object>> listVars, HttpServletRequest request, ResumeResult resumeResult) {
        try {
            // 如果目录不存在，则创建目录
            String filepath = request.getSession().getServletContext().getRealPath("/") + "files"+File.separator;//获取项目路径到webapp
            System.out.println("filepath="+filepath);
            File exportDirs = new File(filepath);
            if (!exportDirs.exists()) {
                exportDirs.mkdirs();
            }
            String fileName=resumeResult.getName()+"-个人简历";
            String file=filepath+fileName+".pdf";
            System.out.println("file="+file);
            FileOutputStream outputStream=new FileOutputStream(file);
            generateAll(configurer, templateName, outputStream, listVars,resumeResult);
            outputStream.flush();
            //同时上传到云服务器
            String url = OSSFactory.build().uploadSuffix(FileUtil.getInputStream(new File(file)),fileName,"resume",".pdf");
            System.out.println("url="+url);
            FileInfo fileInfo=new FileInfo();
            fileInfo.setName(fileName);
            fileInfo.setType("pdf");
            fileInfo.setUrl(url);
            fileInfo.setSize(getFileSize(new File(file)));
            return fileInfo;
        } catch (Exception e) {
            LOGGER.error(e.getMessage(), e);
            return null;
        }
    }

    public static String getFileSize(File file) {
        double d;
        DecimalFormat df = new DecimalFormat("#.00");
        long length = file.length();
        if (1024L <= length && length < 1024 * 1024L) {
            d = length / 1024.0F;
            return df.format(d) + "KB";
        } else if (1024 * 1024L <= length && length < 1024 * 1024 * 1024L) {
            d = length / (1024 * 1024.0F);
            return df.format(d) + "MB";
        } else if (1024 * 1024 * 1024L <= length && length < 1024 * 1024 * 1024 * 1024L) {
            d = length / (1024 * 1024 * 1024.0F);
            return df.format(d) + "GB";
        }
        return length + "B";
    }

    private static  SubResumeVo createData(ResumeResult resume){
        SubResumeVo resumeResult2 = new SubResumeVo();
        resumeResult2.setName(resume.getName());
        resumeResult2.setSex(resume.getSex()==1?"男":"女");
        resumeResult2.setBirthday(resume.getBirthday().substring(0,7));
        resumeResult2.setPhone(resume.getPhone());
        resumeResult2.setEducation(resume.getEducation());
        String currentYear=DateUtils.getCurrentTime("yyyy");
        String startYear=resume.getTimeToWork().substring(0,4);
        int year=Integer.parseInt(currentYear)-Integer.parseInt(startYear);
        resumeResult2.setWorkYear(year+"年");
        resumeResult2.setTimeToWork(resume.getTimeToWork().substring(0,7));
        resumeResult2.setAddress(resume.getAddress());
        resumeResult2.setEmail(ValidatorUtils.notEmpty(resume.getEmail())?resume.getEmail():"无");
        resumeResult2.setAvatar(resume.getAvatar());
        resumeResult2.setPersonalSkill(resume.getPersonalSkill());

        //求职期望
        StringBuilder sb=new StringBuilder();
        List<JobExpectResult> jobExpectList=resume.getJobExpectList();
        for (int i=0;i<jobExpectList.size();i++){
            sb.append(resume.getJobStatus()).append("<br/>").append("<br/>")
                    .append(i+1).append("、")
                    .append(jobExpectList.get(i).getPostName()).append("  -  ").append(jobExpectList.get(i).getJobType()==1?"兼职":"全职")
                    .append("期望薪资：").append(jobExpectList.get(i).getExpectSalary())
                    .append("期望行业：").append(jobExpectList.get(i).getIndustryName()).append("<br/>");
        }
        resumeResult2.setJobExpectList(sb.toString());

        //教育经历
        sb=new StringBuilder();
        List<EduExpResult> eduExpList=resume.getEduExpList();
        for (int i=0;i<eduExpList.size();i++){
            sb.append(i+1).append("、")
                    .append(formatDate(eduExpList.get(i).getStartTime())).append(" - ").append(formatDate(eduExpList.get(i).getEndTime())).append(" 就读于 ").append(eduExpList.get(i).getSchool())
                    .append(",").append(eduExpList.get(i).getMajor()).append(",").append(eduExpList.get(i).getEducation()).append("<br/>");
        }
        resumeResult2.setEduExpList(sb.toString());

        //项目经历
        sb=new StringBuilder();
        List<ProExpResult> proExpList=resume.getProExpList();
        for (int i=0;i<proExpList.size();i++){
            sb.append(i+1).append("、")
                    .append(proExpList.get(i).getName()).append("    ")
                    .append(formatDate(proExpList.get(i).getStartDate())).append(" - ").append(formatDate(proExpList.get(i).getEndDate())).append("<br/>")
                    .append("担任角色：").append(proExpList.get(i).getRole()).append("<br/>")
                    .append("项目描述：").append(proExpList.get(i).getDescr()).append("<br/>")
                    .append("项目成绩：").append(proExpList.get(i).getPerformance()).append("<br/>").append("<br/>");
        }
        resumeResult2.setProExpList(sb.toString());

        sb=new StringBuilder();
        List<WorkExpResult> workExpList=resume.getWorkExpList();
        for (int i=0;i<workExpList.size();i++){
            sb.append(i+1).append("、")
                    .append(formatDate(workExpList.get(i).getStartDate())).append(" - ").append(formatDate(workExpList.get(i).getEndDate())).append(" 在 ").append(workExpList.get(i).getCompanyName()).append(" 担任 ").append(workExpList.get(i).getPostName()).append("<br/>")
                    .append("工作内容：").append(workExpList.get(i).getJobContent()).append("<br/>").append("<br/>");
        }
        resumeResult2.setWorkExpList(sb.toString());

        return resumeResult2;
    }

    private static String formatDate(String date){
        return DateUtils.format(DateUtils.stringToDate(date,DateUtils.DATE_TIME_PATTERN),"yyyy.MM");
    }
}
